package com.google.code.p.restrpc.directory;

import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

/**
 * @author dz
 */
public class RemoteServiceDefinition {
    
    private boolean tlsEnabled = false;
    
    private String remoteAddress;
    
    private int remotePort = 80;
    
    private String contextPath;
    
    private int weight = 1;
    
    private String serviceName;
    
    private String[] methodNames;
    
    private AtomicBoolean enabled = new AtomicBoolean(true);
    
    /**
     * @return the tlsEnabled
     */
    public boolean isTlsEnabled() {
        return tlsEnabled;
    }
    
    /**
     * @param tlsEnabled
     *            the tlsEnabled to set
     */
    public void setTlsEnabled(boolean tlsEnabled) {
        this.tlsEnabled = tlsEnabled;
    }
    
    /**
     * @return the remoteAddress
     */
    public String getRemoteAddress() {
        return remoteAddress;
    }
    
    /**
     * @param remoteAddress
     *            the remoteAddress to set
     */
    public void setRemoteAddress(String remoteAddress) {
        this.remoteAddress = remoteAddress;
    }
    
    /**
     * @return the remotePort
     */
    public int getRemotePort() {
        return remotePort;
    }
    
    /**
     * @param remotePort
     *            the remotePort to set
     */
    public void setRemotePort(int remotePort) {
        this.remotePort = remotePort;
    }
    
    /**
     * @return the contextPath
     */
    public String getContextPath() {
        return contextPath;
    }
    
    /**
     * @param contextPath
     *            the contextPath to set
     */
    public void setContextPath(String contextPath) {
        this.contextPath = contextPath;
    }
    
    /**
     * @return the weight
     */
    public int getWeight() {
        return weight;
    }
    
    /**
     * @param weight
     */
    public void setWeight(int weight) {
        if (weight < 1) {
            throw new IllegalArgumentException("'weight' must be >= 1");
        }
        this.weight = weight;
    }
    
    /**
     * @return the serviceName
     */
    public String getServiceName() {
        return serviceName;
    }
    
    /**
     * @param serviceName
     *            the serviceName to set
     */
    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }
    
    /**
     * @return the methodNames
     */
    public String[] getMethodNames() {
        return methodNames;
    }
    
    /**
     * @param methodNames
     *            the methodNames to set
     */
    public void setMethodNames(String[] methodNames) {
        this.methodNames = methodNames;
    }
    
    /**
     * @return the enabled
     */
    public boolean isEnabled() {
        return enabled.get();
    }
    
    /**
     * 
     */
    public void enable() {
        enabled.compareAndSet(false, true);
    }
    
    /**
     * 
     */
    public void disable() {
        enabled.compareAndSet(true, false);
    }
    
    /**
     * @param address
     * @param port
     * @return
     */
    public boolean matches(String serviceName, String address, int port) {
        return (this.serviceName.equals(serviceName) && this.remoteAddress.equals(address) && (this.remotePort == port));
    }
    
    /**
     * @param address
     * @param port
     * @return
     */
    public boolean matches(String address, int port) {
        return (this.remoteAddress.equals(address) && (this.remotePort == port));
    }
    
    public String toServiceUrl() {
        StringBuilder sb = new StringBuilder();
        sb.append(tlsEnabled ? "https://" : "http://");
        if (StringUtils.isEmpty(remoteAddress)) {
            throw new IllegalArgumentException("remoteAddress can't be null or empty!");
        }
        sb.append(remoteAddress);
        if (remotePort != 80) {
            sb.append(':').append(remotePort);
        }
        if (StringUtils.isEmpty(contextPath)) {
            throw new IllegalArgumentException("contextPath can't be null or empty!");
        }
        if (!contextPath.startsWith("/")) {
            sb.append('/');
        }
        sb.append(contextPath);
        if (StringUtils.isEmpty(serviceName)) {
            throw new IllegalArgumentException("serviceName can't be null or empty!");
        }
        if (!serviceName.startsWith("/")) {
            sb.append('/');
        }
        sb.append(serviceName);
        return sb.toString();
    }
    
    public String toFullUrl() {
        StringBuilder sb = new StringBuilder();
        sb.append(tlsEnabled ? "https://" : "http://");
        if (StringUtils.isEmpty(remoteAddress)) {
            throw new IllegalArgumentException("remoteAddress can't be null or empty!");
        }
        sb.append(remoteAddress);
        if (remotePort != 80) {
            sb.append(':').append(remotePort);
        }
        if (StringUtils.isEmpty(contextPath)) {
            throw new IllegalArgumentException("contextPath can't be null or empty!");
        }
        if (!contextPath.startsWith("/")) {
            sb.append('/');
        }
        sb.append(contextPath);
        if (StringUtils.isEmpty(serviceName)) {
            throw new IllegalArgumentException("serviceName can't be null or empty!");
        }
        if (!serviceName.startsWith("/")) {
            sb.append('/');
        }
        sb.append(serviceName);
        if (!serviceName.endsWith("/")) {
            sb.append('/');
        }
        if ((methodNames == null) || (methodNames.length < 1)) {
            throw new IllegalArgumentException("methodNames can't be null or empty!");
        }
        sb.append(methodNames[0]);
        return sb.toString();
    }
    
    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.SIMPLE_STYLE).reflectionToString(this);
    }
}
